﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace PDO.DataPersistence.Core
{
    public interface IPersistableData : ICloneable
    {
        /// <summary>
        /// Accessor for parent object.  
        /// </summary>
        PersistableDataObject Parent { get; set; }

        /// <summary>
        /// Accessor for key unique identifier string based on table name and primary key value.
        /// </summary>
        string DBKey { get; }

        /// <summary>
        /// Refresh PDO contents from original data source.  Used by change subscription 
        /// system to re-load contents on a change notification.
        /// </summary>
        void Refresh();

        /// <summary>
        /// Create a Clone with separate parent/child relationships.  
        /// I.e. a clone that can be modified and saved without affecting original.
        /// </summary>
        IPersistableData Twin(PersistableDataObject parent);

        IPersistableData Clone(Dictionary<int, IPersistableData> callTrace);

        bool IsNew { get; }
        bool IsDirty { get; }
        bool MarkedForDeletion { get; }


        /// <summary>
        /// When set true, automatically grows PersistableDataObjectList as neccesary to accomodate 
        /// index references.
        /// </summary>
        bool AutoExpand { get; set; }

        /// <summary>
        /// Insert or update changes to database.
        /// </summary>
        /// <returns></returns>
        bool Save();

        /// <summary>
        /// Import into database by either updating or inserting as neccessary.
        /// </summary>
        /// <returns>true if successful, false otherwise.</returns>
        bool Import();

        /// <summary>
        /// Root, or top-level, parent object.
        /// </summary>
        PersistableDataObject RootParent { get; }

        /// <summary>
        /// Does this child element form a self-referencing (circular) relationship?
        /// </summary>
        bool IsSelfReference { get; }

        /// <summary>
        /// Does this child element form a self-referencing (circular) relationship?
        /// </summary>
        int NestingLevel { get; }

        /// <summary>
        /// Called by PersistableDataObjectXmlSerializer prior to serialization.
        /// Provides opportunity to add items to IncludePropertyPath, ExcludeType, etc.
        /// </summary>
        void PrepareSerialization();

    }



    public interface IPersistableDataObjectList : IPersistableData, IList
    {
        /// <summary>
        /// Returns database schema and table name in form [schema name].[table name].
        /// </summary>
        string SourceDatabaseTableName { get; }

        /// <summary>
        /// Name of foreign key column in parent object.
        /// </summary>
        string ParentForeignKeyName { get; }

        /// <summary>
        /// Delete from the database all items in list that are marked for deletion, and clear internal deleted items list.
        /// </summary>
        bool FlushDeletedItems();

        /// <summary>
        /// Indexer that supports a wide range of index instructions, allowing filtering and new item creation.
        /// </summary>
        object this[string index] { get; set; }

        /// <summary>
        /// Indexer that supports automatic expansion to size required to support specified index value.
        /// When AutoExpand is true, this list will expand as needed to accommodate index.
        /// </summary>
        new object this[int index] { get; set; }

        /// <summary>
        /// Sort internal list items using provided comparer.
        /// </summary>
        void Sort(IComparer comparer);

        PersistableDataObject CreateNewItem();

        new void Add(object value);



        #region Paging Support

        /// <summary>
        /// Current page in paged-load.
        /// </summary>
        int CurrentPage { get; }

        /// <summary>
        /// Is this the first page?
        /// </summary>
        bool IsFirstPage { get; }

        /// <summary>
        /// Is this the last page?
        /// </summary>
        bool IsLastPage { get; }

        /// <summary>
        /// Is list multi-paged?  I.e. is total length of list greater than page size.
        /// </summary>
        bool IsMultiPaged { get; }

        /// <summary>
        /// Total count of pages in list. 
        /// </summary>
        int PageCount { get; }


        /// <summary>
        /// Advance to first list page. Page size determined by Session.PageSize.
        /// </summary>
        /// <returns>true if more pages remain; false if on last page</returns>
        void MoveFirstPage();

        /// <summary>
        /// Advance to last page. Page size determined by Session.PageSize.
        /// </summary>
        /// <returns>true if more pages remain; false if on last page</returns>
        void MoveLastPage();

        /// <summary>
        /// Advance to next list page. Page size determined by Session.PageSize.
        /// </summary>
        /// <returns>true if more pages remain; false if on last page</returns>
        void MoveNextPage();


        /// <summary>
        /// Move to previous list page. Page size determined by Session.PageSize.
        /// </summary>
        /// <returns>true if more pages remain; false if on last page</returns>
        void MovePreviousPage();

        #endregion

    }

}
